package com.ybwh.datasource.refreshable.spring.boot;

import com.google.common.base.Preconditions;
import com.ybwh.datasource.refreshable.spring.boot.common.RefreshableConfigMapConfigurationProperties;
import com.ybwh.datasource.refreshable.spring.boot.common.RefreshablePropertiesConfigurationProperties;
import com.ybwh.datasource.refreshable.spring.boot.masterslave.RefreshableMasterSlaveRuleConfigurationProperties;
import com.ybwh.datasource.refreshable.spring.boot.sharding.RefreshableShardingRuleConfigurationProperties;
import com.ybwh.datasource.refreshable.spring.boot.util.PropertyUtil;
import io.shardingsphere.core.exception.ShardingException;
import io.shardingsphere.shardingjdbc.util.DataSourceUtil;

import java.beans.ConstructorProperties;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.sql.DataSource;

import lombok.Getter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Getter
@Configuration
@Conditional({SpringBootConfigurationCondition.class})
@EnableConfigurationProperties({RefreshableShardingRuleConfigurationProperties.class, RefreshableMasterSlaveRuleConfigurationProperties.class,
        RefreshableConfigMapConfigurationProperties.class, RefreshablePropertiesConfigurationProperties.class})
public class SpringBootConfiguration implements EnvironmentAware {

    private Environment environment;

    private final RefreshableShardingRuleConfigurationProperties shardingProperties;
    private final RefreshableMasterSlaveRuleConfigurationProperties masterSlaveProperties;


    private final RefreshableConfigMapConfigurationProperties configMapProperties;
    private final RefreshablePropertiesConfigurationProperties propMapProperties;
    private final Map<String, DataSource> dataSourceMap = new LinkedHashMap();

    @Bean
    public DataSource dataSource() throws SQLException {
        return null == this.masterSlaveProperties.getMasterDataSourceName() ?
                new RefreshableShardingDataSource(this)
                : new RefreshableMasterSlaveDataSource(this);
    }

    @Override
    public final void setEnvironment(Environment environment) {
        this.environment = environment;
        this.setDataSourceMap(environment);
    }

    void setDataSourceMap(Environment environment) {
        String prefix = "refreshable.sharding.jdbc.datasource.";
        String dataSources = environment.getProperty(prefix + "names");
        String[] dataSourceArray = dataSources.split(",");

        for (int i = 0; i < dataSourceArray.length; ++i) {
            String each = dataSourceArray[i];

            try {
                Map<String, Object> dataSourceProps = (Map) PropertyUtil.handle(environment, prefix + each.trim(), Map.class);
                Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource properties!");
                DataSource dataSource = DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps);
                this.dataSourceMap.put(each, dataSource);
            } catch (ReflectiveOperationException var10) {
                throw new ShardingException("Can't find datasource type!", var10);
            }
        }

    }

    @ConstructorProperties({"shardingProperties", "masterSlaveProperties", "configMapProperties", "propMapProperties"})
    public SpringBootConfiguration(RefreshableShardingRuleConfigurationProperties shardingProperties,
                                   RefreshableMasterSlaveRuleConfigurationProperties masterSlaveProperties,
                                   RefreshableConfigMapConfigurationProperties configMapProperties,
                                   RefreshablePropertiesConfigurationProperties propMapProperties) {
        this.shardingProperties = shardingProperties;
        this.masterSlaveProperties = masterSlaveProperties;
        this.configMapProperties = configMapProperties;
        this.propMapProperties = propMapProperties;
    }
}